// -----------------------------------------------------------------------
//  <copyright file="CacheRepositoryDecorator.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2024 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2024/3/21 14:30</last-date>
// -----------------------------------------------------------------------

using Microsoft.Extensions.Caching.Distributed;

using OSharp.Filter;
using OSharp.Caching;


namespace DaprPlus.EntityFrameworkCore;

/// <summary>
/// 仓储缓存装饰器
/// </summary>
/// <typeparam name="TEntity">实体类型</typeparam>
/// <remarks>
/// 初始化一个<see cref="CacheRepositoryDecorator{TEntity}"/>类型的新实例
/// </remarks>
public class CacheRepositoryDecorator<TEntity>(IRepository<TEntity> repository, IDistributedCache cache) : IRepository<TEntity> where TEntity : class, IEntity, IAggregateRoot, ICacheable
{
    private readonly Random _random = new();

    /// <summary>
    /// 获取数据上下文
    /// </summary>
    public IDbContext DbContext => repository.DbContext;

    /// <summary>
    /// 获取指定实体主键编号的实体
    /// </summary>
    public async Task<TEntity?> FindAsync<TKey>(TKey id, CancellationToken cancellationToken = default)
    {
        return await repository.FindAsync(id, cancellationToken);
    }

    /// <summary>
    /// 获取所有实体总数量
    /// </summary>
    public Task<int> GetCountAsync(CancellationToken cancellationToken = default)
    {
        return repository.GetCountAsync(cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的实体数量
    /// </summary>
    public Task<int> GetCountAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetCountAsync(specification, cancellationToken);
    }

    /// <summary>
    /// 获取所有实体总数量
    /// </summary>
    public Task<long> GetLongCountAsync(CancellationToken cancellationToken = default)
    {
        return repository.GetLongCountAsync(cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的实体数量
    /// </summary>
    public Task<long> GetLongCountAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetLongCountAsync(specification, cancellationToken);
    }

    /// <summary>
    /// 是否存在指定编号的实体
    /// </summary>
    public Task<bool> AnyAsync(long id, CancellationToken cancellationToken = default)
    {
        return repository.AnyAsync(id, cancellationToken);
    }

    /// <summary>
    /// 是否存在指定规约的实体
    /// </summary>
    public Task<bool> AnyAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.AnyAsync(specification, cancellationToken);
    }

    /// <summary>
    /// 获取符合指定规约的第一个实体
    /// </summary>
    public Task<TEntity?> GetAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetAsync(specification, cancellationToken);
    }

    /// <summary>
    /// 获取符合指定规约的第一个实体投影或默认值
    /// </summary>
    /// <typeparam name="TResult">投影类型</typeparam>
    /// <param name="specification">规约</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task<TResult?> GetAsync<TResult>(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetAsync<TResult>(specification, cancellationToken);
    }

    /// <summary>
    /// 获取符合指定规约的第一个实体投影
    /// </summary>
    public Task<TResult?> GetAsync<TResult>(ISpecification<TEntity> specification, Expression<Func<TEntity, TResult>> selector, CancellationToken cancellationToken = default)
    {
        return repository.GetAsync(specification, selector, cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的实体集合
    /// </summary>
    public async Task<List<TEntity>> GetAllAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        // 只有全表查询才使用缓存
        if (specification.GetType() != typeof(TrueSpecification<TEntity>))
        {
            return await repository.GetAllAsync(specification, cancellationToken);
        }

        var key = GetCacheKey();
        var seconds = _random.Next((int)TimeSpan.FromDays(7 - 1).TotalSeconds, (int)TimeSpan.FromDays(7 + 1).TotalSeconds);
        var entities = await cache.GetAsync(key, () => repository.GetAllAsync(specification, cancellationToken),
            seconds, cancellationToken);
        return entities ?? [];
    }

    /// <summary>
    /// 获取所有符合规约的实体投影集合
    /// </summary>
    /// <typeparam name="TResult">投影类型</typeparam>
    /// <param name="specification">规约</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task<List<TResult>> GetAllAsync<TResult>(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetAllAsync<TResult>(specification, cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的实体投影集合
    /// </summary>
    public Task<List<TResult>> GetAllAsync<TResult>(ISpecification<TEntity> specification, Expression<Func<TEntity, TResult>> selector, CancellationToken cancellationToken = default)
    {
        return repository.GetAllAsync(specification, selector, cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的分页实体集合
    /// </summary>
    public Task<PageResult<TEntity>> GetPageAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetPageAsync(specification, cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的分页实体投影集合
    /// </summary>
    public Task<PageResult<TResult>> GetPageAsync<TResult>(ISpecification<TEntity> specification, Expression<Func<TEntity, TResult>> selector, CancellationToken cancellationToken = default)
    {
        return repository.GetPageAsync(specification, selector, cancellationToken);
    }

    /// <summary>
    /// 获取所有符合规约的分页实体投影集合
    /// </summary>
    public Task<PageResult<TResult>> GetPageAsync<TResult>(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        return repository.GetPageAsync<TResult>(specification, cancellationToken);
    }

    /// <summary>
    /// 查询指定SQL查询
    /// </summary>
    public Task<List<TResult>> FromSql<TResult>(string sql, object? param = null)
    {
        return repository.FromSql<TResult>(sql, param);
    }

    /// <summary>
    /// 查询指定SQL查询
    /// </summary>
    public Task<List<TEntity>> FromSql(FormattableString sql, CancellationToken cancellationToken = default)
    {
        return repository.FromSql(sql, cancellationToken);
    }

    /// <summary>
    /// 插入实体
    /// </summary>
    public async Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        var result = await repository.InsertAsync(entity, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 插入多个实体
    /// </summary>
    public async Task<int> InsertAsync(ICollection<TEntity> entities, CancellationToken cancellationToken = default)
    {
        var result = await repository.InsertAsync(entities, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 更新实体
    /// </summary>
    public async Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        var result = await repository.UpdateAsync(entity, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 更新多个实体
    /// </summary>
    public async Task<int> UpdateAsync(ICollection<TEntity> entities, CancellationToken cancellationToken = default)
    {
        var result = await repository.UpdateAsync(entities, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 批量更新实体
    /// </summary>
    public async Task<int> UpdateBatchAsync(ISpecification<TEntity> specification, Expression<Func<TEntity, TEntity>> updateExpression, CancellationToken cancellationToken = default)
    {
        var result = await repository.UpdateBatchAsync(specification, updateExpression, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 删除实体
    /// </summary>
    public async Task<int> DeleteAsync<TKey>(TKey key, CancellationToken cancellationToken = default)
    {
        var result = await repository.DeleteAsync(key, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 删除实体
    /// </summary>
    public async Task<int> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        var result = await repository.DeleteAsync(entity, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 删除多个实体
    /// </summary>
    public async Task<int> DeleteAsync(ICollection<TEntity> entities, CancellationToken cancellationToken = default)
    {
        var result = await repository.DeleteAsync(entities, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 删除所有符合条件的实体
    /// </summary>
    public async Task<int> DeleteBatchAsync(ISpecification<TEntity> specification, CancellationToken cancellationToken = default)
    {
        var result = await repository.DeleteBatchAsync(specification, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    /// <summary>
    /// 执行指定的SQL语句
    /// </summary>
    /// <param name="sql">执行的SQL语句</param>
    /// <param name="param">SQL参数</param>
    /// <returns></returns>
    public async Task<int> ExecuteSqlCommandAsync(string sql, object? param = null)
    {
        var result = await  repository.ExecuteSqlCommandAsync(sql, param);
        await ClearCacheAsync();
        return result;
    }

    /// <summary>
    /// 执行指定的格式化SQL语句
    /// </summary>
    /// <param name="sql">要执行的格式化SQL语句</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<int> ExecuteSqlCommandAsync(FormattableString sql, CancellationToken cancellationToken = default)
    {
        var result = await repository.ExecuteSqlCommandAsync(sql, cancellationToken);
        await ClearCacheAsync(cancellationToken);
        return result;
    }

    private async Task ClearCacheAsync(CancellationToken cancellationToken = default)
    {
        var key = GetCacheKey();
        await cache.RemoveAsync(key, cancellationToken);
    }

    private string GetCacheKey()
    {
        return $"Entity:{typeof(TEntity).FullName}";
    }

}
